#ifndef EDGETRAVERSAL_HPP
#define EDGETRAVERSAL_HPP

#include "typeAliases.hpp"
#include "meshBase.hpp"

namespace hms
{

enum class EdgeTraversal {
	ordered,
	rowwise,
	blockwise,
	blockwise_alt,
	ordered_secondOrder,
	rowwise_secondOrder,
	rowwise_secondOrder_seamed,
	blockwise_secondOrder,
	blockwise_secondOrder_seamed,
};

template<typename MeshType, typename Callable, typename ... Ts>
void traverseEdges(
	[[maybe_unused]] EdgeTraversal,
	const MeshBase<MeshType>&,
	Callable,
	Ts&& ... args
);

template<typename MeshType, typename Callable1, typename Callable2, typename ... Ts>
void traverseEdgesSecondOrder(
	[[maybe_unused]] EdgeTraversal,
	const MeshBase<MeshType>&,
	const Array<bool, 4, 1>&,
	Callable1,
	Callable2,
	Ts&&... args
);

/** Defines the head of a traversal function, with the correct args etc. */
#define TRAVERSAL_FUNC_FIRST_ORDER(NAME) \
template<typename MeshType, typename Callable, typename ... Ts> \
void NAME( const MeshBase<MeshType>& mesh, Callable func, Ts&& ... args )

#define TRAVERSAL_FUNC_SECOND_ORDER(NAME) \
template<typename MeshType, typename Callable1, typename Callable2, typename ... Ts> \
void NAME( const MeshBase<MeshType>& mesh, Callable1 funcCentral, Callable2 funcMUSCL, Ts&&... args)

#define STRUCTURED_TRAVERSAL_ASSERT \
static_assert( std::is_base_of_v<StructMeshBase<MeshType>, MeshType>, \
	"You tried using a structured traversal method on an unstructured Mesh!" )

TRAVERSAL_FUNC_FIRST_ORDER(orderedTraversal);

TRAVERSAL_FUNC_FIRST_ORDER(rowwiseTraversal);

TRAVERSAL_FUNC_FIRST_ORDER(blockwiseTraversal);

TRAVERSAL_FUNC_FIRST_ORDER(blockwiseTraversalAlt);

TRAVERSAL_FUNC_SECOND_ORDER(orderedTraversal_secondOrder);

TRAVERSAL_FUNC_SECOND_ORDER(rowwiseTraversal_secondOrder);

TRAVERSAL_FUNC_SECOND_ORDER(rowwiseTraversal_secondOrder_seamed);

TRAVERSAL_FUNC_SECOND_ORDER(blockwiseTraversal_secondOrder);

TRAVERSAL_FUNC_SECOND_ORDER(blockwiseTraversal_secondOrder_seamed);

} // end namespace hms

#include "edgeTraversal.tpp"
#include "edgeTraversal_secondOrder.tpp"

#undef TRAVERSAL_FUNC_FIRST_ORDER
#undef TRAVERSAL_FUNC_SECOND_ORDER
#undef STRUCTURED_TRAVERSAL_ASSERT

#endif